Against the spinner
December 2, 2025
6 min read
A spinner is the interface admitting it does not know how long something will take. Sometimes that is honest and correct. Far more often it is a habit — the component we reach for because the data has not arrived yet and we have to render something.
The board I worked on last year took 1.4 seconds to load. We spent a quarter making it faster and got it to 900 milliseconds, which everyone agreed was a good result and nobody could feel. Then we stopped optimising the request and started painting from the local snapshot before it returned, reconciling in the background. Perceived load: zero. Actual request: still 900 milliseconds.
Three questions before you render a spinner
- Do we already know most of the answer? Cached data, the previous page's list, the row the user just clicked — all of it is real content that beats a placeholder.
- Will this finish under 200ms most of the time? Then show nothing. A spinner that flashes for 80 milliseconds is worse than a brief pause; it reads as a glitch.
- Can we let the user keep working? If the answer only affects one region, do not lock the page for it.
Optimism is a design decision, not a technique
Rendering the expected result before the server confirms it is usually filed under performance. It is really a question about consequences. If the action is a toggle, a rename, a reorder — things that essentially never fail, and where failure is cheap to undo — assume success and reconcile quietly.
If the action moves money, deletes something, or sends a message to another person, do not. Those need the pause. The pause is the design.
Optimistic UI is not a rendering trick. It is a claim about how often you are wrong.
Something I wrote on a whiteboard and then had to defend for an hour
When the spinner is right
Long, genuinely unpredictable work — a build, an upload, an export — deserves an honest indicator. But then it should not be a spinner at all. It should be a progress bar with a real number, or a log of what is happening. A spinner tells you the page is not frozen. A log tells you what it is doing. Only one of those is information.
The rule I have settled on: under 200 milliseconds, show nothing. Under two seconds, show the content you already have. Over two seconds, stop spinning and start narrating.